package se.djupfeldt.oscar.logbook.datasource;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.log4j.Logger;

import se.djupfeldt.oscar.logbook.indata.Sentence;
import se.djupfeldt.oscar.logbook.indata.SentenceException;
import se.djupfeldt.oscar.logbook.indata.SentenceParser;

public abstract class DataSource {
    protected static ConcurrentLinkedQueue<String> list;
    private LinkedHashMap<String, SentenceParser> parsers;
    protected Logger log;

    private void run() {
	new Thread("Data Source") {
	    public void run() {
		runLoop();
	    };
	}.start();
    }
    
    public void init() {
	log = Logger.getLogger(getClass());
	list = new ConcurrentLinkedQueue<String>();
	parsers = new LinkedHashMap<String, SentenceParser>();
	
	File parserDir = new File("parsers");
	try {
	    URL[] urls = {new URL("file://" + parserDir.getAbsolutePath())};
	    ClassLoader loader = URLClassLoader.newInstance(urls, getClass().getClassLoader());
	    for (File child : parserDir.listFiles()) {
		if (child.getName().endsWith(".class")) {
		    String className = child.getName().split("\\.")[0];
		    Class<?> clazz = Class.forName(className, true, loader);
		    Constructor<?> constr = clazz.getConstructor();
		    SentenceParser parser = (SentenceParser) constr.newInstance();
		    parsers.put(parser.getID(), parser);
		    log.info("Loaded SentenceParser: " + parser.getID());
		}
	    }
	} catch (MalformedURLException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (ClassNotFoundException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (SecurityException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (NoSuchMethodException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (IllegalArgumentException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (InstantiationException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (IllegalAccessException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	} catch (InvocationTargetException e) {
	    log.error(e.getMessage(), e);
	    System.exit(-1);
	}
    }
    
    public void start() {
	run();
	new Thread("Sentence Parser") {
	    public void run() {
		log.info("Sentence Parsing started.");
		while (isAlive()) {
		    String s = list.poll();
		    if (s == null)
			continue;
		    s = s.trim();
		    if (s.startsWith("$")) {
			Sentence sentence;
			try {
			    sentence = Sentence.getSentence(s);
			    String id = sentence.getID();
			    SentenceParser parser = parsers.get(id);
			    if (parser != null) {
				parser.parse(s);
				System.out.println(s);
			    } else {
				log.warn("Unknown sentence received: " + s);
			    }
			} catch (SentenceException e) {
			    log.error(e.getMessage());
			} catch (Exception e) {
			    log.error(e.getMessage());
			    e.printStackTrace();
			}
		    }
		    try {
			sleep(5);
		    } catch (InterruptedException e) {
		    }
		}
	    };
	}.start();
    }

    protected abstract void runLoop();
    
    public static ConcurrentLinkedQueue<String> getList() {
	return list;
    }
}
